package com.briup.day10;

import com.briup.day07.Stack;

// 外部类
public class Outer {
    /*
        定义在类内部的类，叫做内部类，内部类是外部类的成员，所以在内部类中是能够
        正常的访问到外部类的内容的，同时在成员内部类定义时是可以指定权限修饰符的；
        注意内部类只是一个统称，并不是只能定义类，同时也可以定义接口
            1、成员内部类，和成员方法、成员变量是同级的，
            都是归属于外部类的对象所有，即只能通过外部类的对象进行访问；使用的较少
            2、静态内部类，和类/静态变量、类/静态方法同级的，
            都是直接归属于类所有，能够直接通过外部类的类名进行调用；使用较多
            3、局部内部类，定义在方法内部的内部类，局部内部类，能够直接访问定义在其前面的
            局部变量，但是经过局部内部类访问后的局部变量会变成常量；局部内部类只能在定义它的
            方法或代码块中使用，外部无法使用
            4、匿名内部类，本质上就是一个局部内部类，不过通常情况下指定是实现一个接口，并且没有给
            该接口实现类命名，然后直接给该接口实现类创建对象的行为；最常用
     */
    class Inner {
        // 成员内部类中可以正常的定义成员变量、成员方法等内容
        public void test() {
            System.out.println("这是成员内部类的成员方法");
        }
        // 成员内部类中能够定义静态方法（在jdk16之后可以）
        // 但通常不会在成员内部类中定义静态方法，因为没有意义
        /*public static void main(String[] args) {

        }*/
    }

    // 成员内部接口
    interface FlyAble {
    }

    // record本质上就是一个类，该类会在编译时，自动给你设定的成员变量创建对应的get方法
    // 以及创建对应参数的构造器
    record Student(String name) {
    }

    // static修饰符，只能用于修饰类中的成员，如成员变量、成员方法、成员内部类、匿名代码块
    // 静态内部类，只需要在成员内部类前添加static修饰符即可
    static class StaticInner {
        // 静态内部类中能够定义所有外部类中的内容
        private String name;
        private static final String id = "1";

        static {
            System.out.println("这是静态内部类StaticInner的静态代码块");
        }

        public void test() {
            System.out.println("这是静态内部类StaticInner的成员方法");
        }

        public static void staticMethod() {
            System.out.println("这是静态内部类StaticInner的静态方法");
        }
    }

    // 通常情况下可以将外部类中需要使用的，并且只有该外部类会用到的代码结构
    // 在外部类中定义成一个静态内部类，然后根据是否需要对外暴露，选择该外部类的权限修饰符

    // abstract可以和static一起修饰定义一个静态的内部抽象类
    public abstract static class StaticClass {
        public abstract void method();
    }
}

class SubOuter {
    public static class StaticClass2 extends Outer.StaticClass {
        @Override
        public void method() {
            System.out.println("重写从父类中继承下来的抽象静态内部类中的抽象方法");
        }
    }
}

class Test04 {
    public static void main(String[] args) {
        // 如果要使用Outer内部的成员内部类，需要先创建Outer类的对象
        Outer outer = new Outer();
        // 然后通过外部类的对象调用创建内部类对象的行为
        Outer.Inner inner = outer.new Inner();
        Outer.Student student = new Outer.Student("张三");
        // 相当于调用getName()方法
        System.out.println(student.name());
        System.out.println(student);
        testInner();
        testAnonymousInner();
    }

    private static void testInner() {
        int a = 100;
        // 定义在方法、代码块内部的内部类叫做局部内部类
        class Inner {
            public void test() {
                System.out.println(a);
            }
        }
        // 局部内部类的使用范围，只能是在定义它的那个方法/代码块内部
        Inner inner = new Inner();
        inner.test();
        // 给变量a重新赋值，注意这里因为变量a被局部内部类访问过，所以变量a变成了常量，所以不能被重新赋值
        // a = 10;
        System.out.println(a);
    }

    private static void testAnonymousInner() {
        // enroll方法的调用需要传入一个会飞的成员
        Test02.enroll(new Bat());
        // 需要传入的是如Bird、Plane、Bat等Flyable接口的实现类
        // 传入纸飞机，Flyable作为接口来说，是不能创建对象的，
        // 这里创建的是Flyable接口的实现类对象，只不过该接口实现类没有名字
        Test02.enroll(new Flyable() {
            @Override
            public void fly() {
                System.out.println("纸飞机划过天际");
            }
        });
    }
}
